// ==UserScript==
// @name         海外问卷答题脚本
// @version      0.1
// @match        *://*/*
// @run-at       document-start
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_deleteValue
// @grant        GM_addValueChangeListener
// @grant        GM_xmlhttpRequest
// ==/UserScript==

const 后端地址 = 'http://localhost:3000'
const 后端消息入口 = `${后端地址}/前端消息接入点`

const { host: 站点 } = location
let 用户ID = GM_getValue('用户ID'), 我的用户名

const 信息查 = new Map
信息查.执行 = function (变动) { 信息查.forEach((查, 查之名) => 是函数(查) && 查.call(this, 变动)?.done && 信息查.delete(查之名)) }

const cssTop = () => (cssTop.v ??= -1, `${++cssTop.v * 3}rex`), zbc = `z-index:999999999; background-color:#0C3040; color:#fff;`

const 巨字 = 'font-size:xx-large'
const 大字 = 'font-size:x-large'
console.巨字 = (文本, 附加样式 = '') => console.log(`%c${文本}`, `${巨字};${附加样式}`)
console.大字 = (文本, 附加样式 = '') => console.log(`%c${文本}`, `${大字};${附加样式}`)


let body, html
document.addEventListener('DOMContentLoaded', async () => {
  ({ body, documentElement: html } = document)
  试行(功能之黑暗主题)
  试行(功能之显示已启动时长)
  GM_addValueChangeListener('ip已变', (_1, _2, _3, 来自别页) => (来自别页 ? alert : console.大字)('【终止提示】IP 已变！！'))

  if (站点 === 'start.adspower.net' || 站点 === '127.0.0.1:20725') {
    if (站点 === '127.0.0.1:20725') document.querySelector('.time').style.zIndex = 2
    if (站点 === 'start.adspower.net') await 监察(() => document.body.innerText.includes('启动时间'))
    const { 启动时间 } = document.body.innerText.replace(/[^]*?(启动时间)[:\n]*(.+?:\d+\n)[^]*/, '$1:$2')._asKVObj
    GM_setValue('启动时间', 启动时间)
    console.巨字('已启动时长：' + 已启动时长._innerText)
    检查ip变否 = async () => {
      let 原ip, 初ip
      const ip栏选择器 = '127.0.0.1:20725' ? '.ip-ip' : 'span[class^=_header__ip]'
      初ip = 站点 === '127.0.0.1:20725' ? 获取网址参数('ip') : (await 监察(ip栏选择器, (变动, 元素选择器) => { const 元素 = 变动.target._qS?.(元素选择器); return 元素 && 元素.innerText !== '---.---.---.---' && 元素 })).innerText
      console.巨字(`IP：${初ip}`)
      原ip = GM_getValue('ip') || (GM_setValue('ip', 初ip), 初ip)
      const 检测ip变否 = (新ip = 初ip) => 新ip !== 原ip && GM_setValue('ip已变', Math.random() /* 已启动时长._innerText */)
      检测ip变否()
      监察(ip栏选择器, ({ target: { innerText } }) => 检测ip变否(innerText))
    }
    检查ip变否()
  }

  else {
    addEventListener('click', throttle(e => {
      let 点击的元素选择器
      try { 点击的元素选择器 = cssPath(e.target) } catch (e) { console.error(e) }
      点击的元素选择器 && 向后端发信({ 意图: '广播:用户点击', 数据: { 操作的用户: 我的用户名, 元素选择器: 点击的元素选择器 } })
    }))

    if (站点 === 'oneplus.sample-cube.com') {
    }
    else if (站点 === 'whoer.net') {
      监察(信息查.执行)
      GM_deleteValue(站点)
      const 信标选择器 = '[data-fetched=postal_code]', 信标元素 = body.querySelector(信标选择器)
      信息查.set(
        站点,
        function (变动) {
          if (!(信标元素.innerText.trim() && 变动.target.matches('.ip-info.location-info'))) return
          const 目标根元素 = 变动.target.querySelector('.icon_location').parentNode
          const 目标元素数 = 目标根元素.querySelectorAll('.card__row').findIndex(一级子元素 => 一级子元素.querySelector(信标选择器)) + 1
          const 目标元素们 = 目标根元素.querySelectorAll(`.card__row:nth-child(-n+${目标元素数})`)
          let 目标元素文 = []
          目标元素们.forEach(元素 => 元素.innerText && 目标元素文.push(元素.innerText._asKV))
          目标元素文 = 目标元素文._asObjStr
          GM_setValue('地理信息', 目标元素文)
          console.log(`地理信息：`, 目标元素文._asObj)
          return { done: true }
        }
      )
    }
    else if (站点.includes('jasonclix')) {
      切样式(`form>form-group:first-child{cursor: not-allowed} input{pointer-events: none}`)
    }
    else {
      if (站点.includes('spectrumsurveys')) {
        试行(() => {
          用户ID = 获取网址参数('supplierMemberId').replace(/-.*/, '')
          GM_setValue('用户ID', 用户ID)
        })
      }
      else if (站点.includes('redclive')) {
        //【功能】整个选项条可点击
        document.querySelectorAll('[onclick]').forEach(_ => _.closest('tr').onclick = _.onclick)
      }
    }
  }
})


监察变动.组计数 = 0
监察变动.子计数 = 0

unsafeWindow.向后端发信 = function 向后端发信(数据) {
  return GM_fetch(后端消息入口, {
    method: 'POST',
    body: 字串化(数据),
    headers: { 'Content-Type': 'application/json' }
  })
}

async function 监察变动(变动) {
  const { target: 变者 } = 变动
  const 报告 = { 用户ID, site: 站点, type: 变动.type }
  ++监察变动.子计数;; /* console.log('监察变动.子:', 监察变动.子计数) */
  return
  switch (变动.type) {
    case 'attributes': 报告.attr = 变者.attributeName; break
    case 'characterData': 报告.char = 变者._ ?? '??'; break
    case 'childList': if (变动.addedNodes.length); break
  }
  try {
    const 结果 = await 查库(报告)
    if (!结果) return
    结果(变者)
  } catch (e) { console.error('查库没得', e) }
}

const 事件源 = new EventSource(后端消息入口)
事件源.addEventListener('open', () => {
  console.巨字('前后端通讯已建立！', 'color:green')
  向后端发信({ 意图: '广播:用户点击', 数据: { 用户ID } })
})
事件源.addEventListener('message', ({ data }) => {
  try { data = JSON.parse(data) } catch (e) { console.error('服务器传来的数据在发来前请先转成 JSON 格式！') }
  const { 意图, 数据 } = data
  switch (意图) {
    case '我的用户名': 我的用户名 = 数据; break
  }
})
事件源.addEventListener('error', e => {
  // 不要执行： 事件源.close()
  console.error(e)
  console.巨字('你未启动“海问”终端程序噢', 'color:red;background-color:yellow')
})

async function 查库(键) {
  ws.send(字串化(键))
  return await new Promise((返, 拒) => {
    ws.addEventListener('message', ({ data }) => {
      const packet = JSON.parse(data)
      console.log(packet)
      返(data)
    }, { once: true })
    setTimeout(拒, 查库.超时)
  })
}
查库.超时 = 2000



function 当前页的交卷() {
  const 答 = (document.querySelectorAll('form') || body).cloneNode(true)
  答.querySelectorAll('input[type=checkbox]:not(:checked)').forEach(_ => _.closest('label').remove())
  return 答.textContent
}

function 功能之显示已启动时长() {
  if (!GM_getValue('启动时间')) {
    GM_addValueChangeListener('启动时间', 功能之显示已启动时长)
    return
  }
  const 已启动时长 = body.insertAdjacentElement('beforeend', Object.assign(document.createElement('海问元素'), {
    innerHTML: `
<style>
#已启动时长 {
  position: fixed;
  right: 0;
  bottom: 0;
  ${zbc}
  border-top-left-radius: 0.5ch;
  padding: .2rem .25rem 0;
  font-family: "Segoe UI";
}
</style>
<div id="已启动时长"></div>
  `
  })).querySelector('#已启动时长')
  更新显示()
  function 更新显示() {
    已启动时长._innerText = 功能之显示已启动时长.计算()
    if (已启动时长.innerText !== 已启动时长._innerText) 已启动时长.innerText = 已启动时长._innerText
    requestAnimationFrame(更新显示)
  }
}
功能之显示已启动时长.计算 = (启动时间 = GM_getValue('启动时间')) => 日期.时间差(启动时间, 日期.中国)


function 功能之黑暗主题() {
  const 框 = html.insertAdjacentElement('beforeend', Object.assign(document.createElement('海问元素'), {
    innerHTML: `
<style>
  .暗黑主题框 {position:absolute;right:0;top:${cssTop()};${zbc};border-bottom-left-radius:0.5ch;padding-left:0.1rem}
  .暗黑主题框>label {margin:0}
</style>
<div class="暗黑主题框">
  <input type="checkbox" id="暗黑主题按钮">
  <label for="暗黑主题按钮">强制深色</label>
</div>
  `,
    onclick: (e) => {
      if (e.target.localName !== 'input') return
      const 开 = e.detail?.开 ?? e.target.checked
      切样式(`
:root {
  --bg: #202124;
  --cl: #e8eaed;
}
*:not(a):not(a>*):not(b):not(svg):not(svg *):not([class*=icon]):not(button):not(button *):not(.button):not(.button *):not(:not(input):not([style]):empty):not(font):not([style^=background]):not([style^=background] *):not([class*=_header]):not([class*=_header] *):not([class*=__wrap]):not(:checked+span):not(img):not(img+[style]):not([class$=overlay]):not(.progress-bar) {
  background-color: var(--bg) !important;
  color: var(--cl) !important;
}

a:not([class*=button]) {
  color: #8ab4f8 !important;
}
a:not([class*=button]):visited {
  color: #c58af9 !important;
}
a:not([class*=button])>span {
  color: var(--cl);
}

/*<title>供应商路由器筛选器 */
li:hover > div > a,
form.container.survey_complete.ng-untouched.ng-pristine.ng-invalid label:hover > span:not(:checked+span) {
  background-color: #6666 !important;
}
/* 供应商路由器筛选器</title> */




.progress-bar {
  background: linear-gradient(to right, red 20%, yellow 70%, green 100%) fixed;
}
.progress-bar-number {
  font-size: larger;
}

#innerLeftNav:hover, #innerRightNav:hover, .prev-button:hover, .next-button:hover {
  background: linear-gradient(#7C7C7C, #424045) !important;
}

.next-button.disabled {
  display: none;
}

[id^=inner][id$=Nav]:hover *, .prev-button:hover *, .next-button:hover * {
  background-color: unset !important;
}

#singleColumnRadio > tbody > tr:hover * {
  cursor: pointer;
  background-color: #7777 !important;
}

body.desktop .header-container .progress {
  border-color: #777;
}
`, { 开, target: e.target })
      GM_setValue('黑暗主题', 开)
    }
  }))
  const input = 框.querySelector('input')
  console.log('强制深色主题：', eval(GM_getValue('黑暗主题')))
  eval(GM_getValue('黑暗主题')) && (触发(input, 'click', { 开: true }), input.checked = true)
}

